package com.xinqi.common.redis.utils;

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @author linkai
 * @since 2023/02/15
 */
public interface Caches {
    long DEFAULT_TIME_TO_LIVE = 10 * 60;

    static String formatKey(String key, Object... args) {
        return String.format(key, args);
    }

    static <T> RBucket<T> getBucket(RedissonClient redissonClient, String key, Object... args) {
        return redissonClient.getBucket(formatKey(key, args));
    }

    static <T> T get(Supplier<T> s, RedissonClient redissonClient, String key, Object... args) {
        return get(getBucket(redissonClient, key, args), s);
    }

    static <T> T get(Supplier<T> s, long timeToLive, RedissonClient redissonClient, String key, Object... args) {
        return get(getBucket(redissonClient, key, args), s, timeToLive);
    }

    static <T> T get(RBucket<T> bucket, Supplier<T> s, long timeToLive) {
        T o;
        if (exists(bucket)) {
            o = bucket.get();
        } else {
            o = s.get();
            if (o == null) {
                return null;
            }
            bucket.set(o, timeToLive, TimeUnit.SECONDS);
        }
        return o;
    }

    static <T> T get(RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> bucket = getBucket(redissonClient, key, args);
        if (exists(bucket)) {
            return bucket.get();
        }
        return null;
    }

    static <T> T get(RBucket<T> bucket, Supplier<T> s) {
        return get(bucket, s, DEFAULT_TIME_TO_LIVE);
    }

    static <T> boolean exists(RBucket<T> bucket) {
        return bucket.isExists();
    }

    static <T> void set(T o, long timeToLive, RedissonClient redissonClient, String key, Object... args) {
        set(getBucket(redissonClient, key, args), o, timeToLive);
    }


    static <T> void setIfExist(T o, long timeToLive, RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> bucket = getBucket(redissonClient, key, args);
        if (exists(bucket)) {
            set(bucket, o, timeToLive);
        }
    }

    static <T> void set(T o, RedissonClient redissonClient, String key, Object... args) {
        set(getBucket(redissonClient, key, args), o, DEFAULT_TIME_TO_LIVE);
    }

    static <T> void set(RBucket<T> bucket, T o, long timeToLive) {
        bucket.set(o, timeToLive, TimeUnit.SECONDS);
    }

    static <T> boolean del(RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> bucket = getBucket(redissonClient, key, args);
        if (bucket == null || !bucket.isExists()) {
            return true;
        }
        return bucket.delete();
    }

    static <T> long getTimeToLive(RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> rBucket = getBucket(redissonClient, key, args);
        return rBucket.remainTimeToLive();
    }

    static <T> boolean setTimeToLive(long timeout, RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> rBucket = getBucket(redissonClient, key, args);
        return rBucket.expire(Duration.ofSeconds(timeout));
    }

    static <T> boolean setIfAbsent(T o, long timeToLive, RedissonClient redissonClient, String key, Object... args) {
        RBucket<T> rBucket = getBucket(redissonClient, key, args);
        if (timeToLive > 0) {
            return rBucket.setIfAbsent(o, Duration.ofSeconds(timeToLive));
        }
        return rBucket.setIfAbsent(o);
    }

}
